package com.g2room.net;

import com.g2room.io.grep.HttpUtil;
import com.g2room.system.SystemUtil;
import com.google.common.collect.Lists;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URL;
import java.util.List;
import java.util.Properties;

public class Ping {
    public static final String HTTP = "http://";
    public static final String HTTPS = "https://";
    /**
     * win系统ping不通错误提示
     */
    public static final String PING_WIN_NOT_KONW = "请求找不到主机";
    /**
     * Linux系统ping不通错误提示
     */
    public static final String PING_LINUX_NOT_KONW = "Name or service not known";

    /**
     * public static String getProperty(String key)
     * 键               相关值的描述
     * java.version    Java 运行时环境版本
     * java.vendor     Java 运行时环境供应商
     * java.vendor.url     Java 供应商的 URL
     * java.home   Java 安装目录
     * java.vm.specification.version   Java 虚拟机规范版本
     * java.vm.specification.vendor    Java 虚拟机规范供应商
     * java.vm.specification.name  Java 虚拟机规范名称
     * java.vm.version     Java 虚拟机实现版本
     * java.vm.vendor  Java 虚拟机实现供应商
     * java.vm.name    Java 虚拟机实现名称
     * java.specification.version  Java 运行时环境规范版本
     * java.specification.vendor   Java 运行时环境规范供应商
     * java.specification.name     Java 运行时环境规范名称
     * java.class.version  Java 类格式版本号
     * java.class.path     Java 类路径
     * java.library.path   加载库时搜索的路径列表
     * java.io.tmpdir  默认的临时文件路径
     * java.compiler   要使用的 JIT 编译器的名称
     * java.ext.dirs   一个或多个扩展目录的路径
     * os.name     操作系统的名称
     * os.arch     操作系统的架构
     * os.version  操作系统的版本
     * file.separator  文件分隔符（在 UNIX 系统中是“/”）
     * path.separator  路径分隔符（在 UNIX 系统中是“:”）
     * line.separator  行分隔符（在 UNIX 系统中是“/n”）
     * user.name   用户的账户名称
     * user.home   用户的主目录
     * user.dir    用户的当前工作目录
     */
    public static void getSystemInfo() {
        Properties props = System.getProperties(); //获得系统属性集
        String osUser = System.getProperty("user.name"); //获取操作系统账户
        String osName = props.getProperty("os.name"); //操作系统名称
        String osArch = props.getProperty("os.arch"); //操作系统构架
        String osVersion = props.getProperty("os.version"); //操作系统版本
        System.out.println(osUser);
        System.out.println(osName);
        System.out.println(osArch);
        System.out.println(osVersion);
    }

    /**
     * 判断网络是否正常。根据网络情况进行打分。满分100分
     *
     * @return
     */
    public static int isConnect(String ipPath) {
        //定义其返回的状态，默认为false，网络不正常
        boolean isWindows = SystemUtil.isWindows();
        int rs = 0;
        Process process;
        InputStream is = null;
        BufferedReader br = null;
        InputStreamReader isr = null;
        try {
            process = Runtime.getRuntime().exec("ping " + (isWindows ? "-n" : "-c") + " 1 " + ipPath);
            is = process.getInputStream();
            isr = new InputStreamReader(is, "GBK");
            br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                // 获取数据包和RTT时间来判断网络速度和稳定性
                if (isWindows) {
                    if (line.contains(PING_WIN_NOT_KONW)) {
                        return 0;
                    }
                    rs = calculateWinRs(rs, line);
                } else {
                    if (line.contains(PING_LINUX_NOT_KONW)) {
                        return 0;
                    }
                    rs = calculateLinuxRs(rs, line);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != isr) {
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return rs > 0 ? rs : 0;
    }

    private static int calculateWinRs(int rs, String line) {
        if (line.contains("数据包")) {
            // 判断丢包率。丢包率分数占比为 70%。
            // 截取丢失率
            String loss = line.substring(line.indexOf("(") + 1, line.indexOf("%"));
            rs = 100 - Integer.parseInt(loss);
        } else if (line.contains("平均")) {
            // 判断往返行程的估计时间。此项占比为30%
            // 定义<= 100ms为正常；差不多如果平均时间为10S（10000ms）时，网络基本处于不可用状态
            String ageTTL = line.substring(line.indexOf("平均 = ") + 5, line.lastIndexOf("ms"));
            rs -= Integer.parseInt(ageTTL) / 50;
        }
        return rs;
    }

    private static int calculateLinuxRs(int rs, String line) {
        if (line.contains("packets")) {
            // 判断丢包率。丢包率分数占比为 70%。
            // 截取丢失率
            String loss = line.substring(line.indexOf("received, ") + 10, line.lastIndexOf("%"));
            rs = 100 - Integer.parseInt(loss);
        } else if (line.contains("rtt")) {
            // 判断往返行程的估计时间。此项占比为30%
            // 定义<= 100ms为正常；差不多如果平均时间为10S（10000ms）时，网络基本处于不可用状态
            String ageTTL = line.substring(line.lastIndexOf("="), line.lastIndexOf("/"));
            ageTTL = ageTTL.substring(ageTTL.lastIndexOf("/") + 1);
            rs -= Integer.parseInt(ageTTL) / 50;
            rs = rs > 0 ? rs : 0;
        }
        return rs;
    }

    /**
     * 传入需要连接的IP或域名，返回是否连接成功
     *
     * @param remoteInetAddr
     * @return
     */
    public static boolean isReachable(String remoteInetAddr) {
        boolean reachable = false;
        try {
            // 处理前缀的http或https
            reachable = InetAddress.getByName(handleHttpPre(remoteInetAddr)).isReachable(5000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return reachable;
    }

    /**
     * 去掉http或https前缀
     * @param addr
     * @return
     */
    private static String handleHttpPre(String addr) {
        if (addr.contains(HTTPS)) {
            return addr.substring(8);
        }
        if (addr.contains(HTTP)) {
            return addr.substring(7);
        }
        return addr;
    }

    /**
     * 查看是否可以连接。需要在url前加 http或https
     * 不推荐使用此方法
     *
     * @param urlStr
     * @return
     */
    public static boolean canConnect(String urlStr) {
        boolean reachable = false;
        InputStream in = null;
        try {
            URL url = new URL(urlStr);
            in = url.openStream();
            reachable = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return reachable;
    }

    public static void main(String[] args) {
        List<String> urls = Lists.newArrayList("https://www.baidu.com", "http://www.baidu.com", "www.163.com", "www.github.com", "www.youtube.com", "www.google.com");
//        urls = Lists.newArrayList("192.168.0.9","192.168.0.239");
//        urls.forEach(x -> System.out.println(x + " = " + Ping.isConnect(x)));
        urls.forEach(x -> System.out.println(x + " = " + Ping.isReachable(x)));
        urls.forEach(x -> System.out.println(x + " = " + Ping.canConnect(x)));
//        System.out.println(Ping.isNodeReachable("www.baidu.com"));
    }
}
